﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using GP.Scripts.Battle;
using Gp.Scripts.Data;
using Gp.Scripts.Equip;

namespace Gp.Scripts.Core
{
    public class UnitEquipCom : IUnitComponent
    {
        public BaseUnit Unit;

        public WeaponEntity[] Weapons;
        public WeaponEntity CurWeapon => Weapons[CurWeaponIndex];


        private int _curWeaponIndex = 0;

        public int CurWeaponIndex
        {
            get => _curWeaponIndex;
            private set => _curWeaponIndex = Math.Clamp(value, 0, Weapons.Length);
        }


        private UnitEquip EquipData => null;


        private List<ArmorFragmentEntity> _armorFragments;
        public IEnumerable<ArmorFragmentEntity> ArmorList => _armorFragments;


        #region Init

        // 单位技能由装备提供
        public void Init(BaseUnit unit)
        {
            Unit = unit;
            // 读取武器
            var equipGroupId     = unit.EntityConfig.EquipGroup;
            var groupConfig = Global.GetConfig<Unit.TableEquipGroup>().Get(equipGroupId);
            this.Weapons = new WeaponEntity[groupConfig.Weapons.Count];
            for (var i = 0; i < groupConfig.Weapons_Ref.Count; i++)
            {
                Weapons[i] = new WeaponEntity(groupConfig.Weapons_Ref[i], this);
            }
            //
            // LoadAbilitiesProcess();
            // LoadEquipmentProcess();
        }

        private void LoadAbilitiesProcess()
        {
            var unit      = Unit;
            var equipData = EquipData;


            foreach (var ability in equipData.equipAbility)
            {
                if (ability == null) continue;
                var skill = ability.BuildSkill();
                unit.ComSkill.AddSkill(skill);
            }

            foreach (var magic in equipData.equipMagic)
            {
                if (magic == null) continue;
                unit.ComSkill.AddSkill(magic.BuildSkill());
            }


            foreach (var buff in equipData.buffData)
            {
                if (buff == null) continue;
                Unit.ComBuff.AddBuff(buff.BuildBuff());
            }
        }

        private void LoadEquipmentProcess()
        {
            var armorProviders = new List<IArmorProvider>();

            Weapons = new WeaponEntity[2];
            var defaultWeapon = Global.Get<BattleSystem>().RulesModel.DefaultWeapon;
            for (int i = 0; i < Weapons.Length; i++)
            {
                if (i < EquipData.weaponEquips.Length && EquipData.weaponEquips[i] != null)
                    Weapons[i] = new WeaponEntity(EquipData.weaponEquips[i], this);
                else
                    Weapons[i] = new WeaponEntity(defaultWeapon, this);

                OnAddWeapon(Weapons[i]);
                // if (Weapons[i].Info is IArmorProvider p) armorProviders.Add(p);
            }

            CurWeaponIndex = 0;

            armorProviders.Add(new PileArmorEntity(EquipData.ArmorEquip, Unit));
            _armorFragments = armorProviders.SelectMany(x => x.ArmorFragments).ToList();
            // 排序，将护盾提供的护甲排列在前
            _armorFragments.Sort((a1, a2) =>
            {
                int v1 = a1.IsShieldFragment ? 1 : 0;
                int v2 = a2.IsShieldFragment ? 1 : 0;
                return v2 - v1;
            });
        }

        #endregion


        #region Weapon

        private void OnAddWeapon(WeaponEntity weapon)
        {
            // foreach (var buffData in weapon.Config.buffs)
            // {
            //     Unit.AddBuff(buffData.BuildBuff());
            // }

            foreach (var skill in weapon.WeaponAbilities())
            {
                Unit.ComSkill.AddSkill(skill);
            }
        }


        public bool CanAttack()
        {
            // return CurWeapon.Info.CanAttack();
            return true;
        }


        public void ChangeCurWeapon(int nextIndex)
        {
            nextIndex = Math.Clamp(nextIndex, 0, Weapons.Length);
            if (nextIndex == _curWeaponIndex) return;


            MainArchitecture.Interface.SendEvent(new WeaponChangeEvent(_curWeaponIndex, nextIndex, this));
            _curWeaponIndex = nextIndex;


            Unit.Model.GestureTrigger(new ChangeWeaponGestureTrigger(CurWeapon));
        }

        #endregion


        #region Armor

        /// <summary>
        /// 获取护甲防御，返回护甲板防御力总和
        /// </summary>
        /// <returns></returns>
        public int GetArmorPoint()
        {
            return ArmorList
                .Where(a => !a.IsBroken)
                .Sum(a => a.CurDurability);
        }


        public ArmorFragmentEntity GetArmor(int index = 1)
        {
            int count = 0;
            return ArmorList.Where(info => !info.IsBroken).FirstOrDefault(_ => ++count == index);
        }


        /// <param name="index">第几块装甲板</param>
        /// <returns></returns>
        public ArmorFragmentEntity GetPileArmor(int index = 1)
        {
            // 从左到右选取未损坏的护甲板
            int count = 0;
            return ArmorList
                .Where(info => !info.IsBroken && !info.IsShieldFragment)
                .FirstOrDefault(_ => ++count == index);
        }


        public List<ArmorFragmentEntity> AllArmor()
        {
            return new List<ArmorFragmentEntity>(ArmorList);
        }


        // 当前护甲板数量
        public int ArmorCount()
        {
            return ArmorList.Count(x => !x.IsBroken);
        }


        public IEnumerable<ArmorFragmentEntity> GetShieldArmors()
        {
            return ArmorList.Where(x => x.IsShieldFragment && !x.IsBroken);
        }


        public int GetShieldArmorPoints()
        {
            return GetShieldArmors().Sum(x => x.CurDurability);
        }


        public int MaxArmorPoints()
        {
            return ArmorList.Sum(x => x.FullValue());
        }


        public bool HasShield()
        {
            return GetShieldArmorPoints() > 0;
        }

        public bool HasArmor()
        {
            return GetArmorPoint() > 0;
        }

        #endregion


        #region TurnState

        public IEnumerator OnTurnStart()
        {
            // return this.Weapons.Select(weapon => weapon.SmallTurnStart(state)).GetEnumerator();
            yield break;
        }

        public IEnumerator OnTurnEnd()
        {
            // foreach (var weapon in this.Weapons)
            // {
            //     weapon.SmallTurnEnd(state);
            // }

            yield break;
        }


        public IEnumerable<BonusInfo> Bonus()
        {
            yield return new BonusInfo(CurWeapon.Bonus(), CurWeapon);
        }

        #endregion

        public void OnDestroy()
        {
            // _armorFragments.Clear();
        }
    }

    public class WeaponChangeEvent
    {
        public WeaponChangeEvent(int last, int next, UnitEquipCom ComEquip)
        {
            ComEquip  = ComEquip;
            LastIndex = last;
            NextIndex = next;

            Last = ComEquip.Weapons[last];
            Cur  = ComEquip.Weapons[next];
        }

        public UnitEquipCom ComEquip { get; }

        public WeaponEntity Last { get; }
        public WeaponEntity Cur { get; }
        public int LastIndex { get; }
        public int NextIndex { get; }
    }
}